#include <gtest/gtest.h>
#include "protocol/JsonRpcMessageParser.h"
#include <QJsonObject>
#include <QJsonArray>
#include <QJsonValue>
#include <QVariant>

/**
 * @brief Test class for JsonRpcMessageParser
 * @details Tests the JSON-RPC message parser implementation including
 * validation, parsing, and type detection according to JSON-RPC 2.0 specification
 */
class TestJsonRpcMessageParser : public ::testing::Test
{
protected:
    void SetUp() override
    {
        mParser = std::make_unique<JsonRpcMessageParser>();
    }
    
    void TearDown() override
    {
        mParser.reset();
    }
    
    QJsonObject createValidRequest(const QString& method = "testMethod",
                                  const QJsonValue& params = QJsonValue(),
                                  const QVariant& id = QVariant(1));
    QJsonObject createValidResponse(const QVariant& id = QVariant(1),
                                   const QJsonValue& result = QJsonValue("success"));
    QJsonObject createValidNotification(const QString& method = "testNotification",
                                      const QJsonValue& params = QJsonValue());
    QJsonObject createErrorResponse(const QVariant& id = QVariant(1),
                                  int code = -32600,
                                  const QString& message = "Invalid Request",
                                  const QJsonValue& data = QJsonValue());
    
    std::unique_ptr<JsonRpcMessageParser> mParser;
};

TEST_F(TestJsonRpcMessageParser, ValidateValidRequest)
{
    QJsonObject request = createValidRequest();
    
    EXPECT_TRUE(mParser->validateMessage(request));
}

TEST_F(TestJsonRpcMessageParser, ValidateValidRequestWithArrayParams)
{
    QJsonArray paramsArray = QJsonArray{"param1", "param2", "param3"};
    QJsonObject request = createValidRequest("testMethod", paramsArray);
    
    EXPECT_FALSE(mParser->validateMessage(request)); // Array params are now invalid
}

TEST_F(TestJsonRpcMessageParser, ValidateValidRequestWithObjectParams)
{
    QJsonObject paramsObject;
    paramsObject["param1"] = "value1";
    paramsObject["param2"] = 42;
    QJsonObject request = createValidRequest("testMethod", paramsObject);
    
    EXPECT_TRUE(mParser->validateMessage(request));
}

TEST_F(TestJsonRpcMessageParser, ValidateValidRequestWithStringId)
{
    QJsonObject request = createValidRequest("testMethod", QJsonValue(), "request-123");
    
    EXPECT_TRUE(mParser->validateMessage(request));
}

TEST_F(TestJsonRpcMessageParser, ValidateValidResponse)
{
    QJsonObject response = createValidResponse();
    
    EXPECT_TRUE(mParser->validateMessage(response));
}

TEST_F(TestJsonRpcMessageParser, ValidateValidErrorResponse)
{
    QJsonObject errorResponse = createErrorResponse();
    
    EXPECT_TRUE(mParser->validateMessage(errorResponse));
}

TEST_F(TestJsonRpcMessageParser, ValidateValidNotification)
{
    QJsonObject notification = createValidNotification();
    
    EXPECT_TRUE(mParser->validateMessage(notification));
}

TEST_F(TestJsonRpcMessageParser, ValidateInvalidJsonRpcVersion)
{
    QJsonObject request = createValidRequest();
    request["jsonrpc"] = "1.0"; // Invalid version
    
    EXPECT_FALSE(mParser->validateMessage(request));
}

TEST_F(TestJsonRpcMessageParser, ValidateMissingJsonRpcVersion)
{
    QJsonObject request = createValidRequest();
    request.remove("jsonrpc"); // Missing version
    
    EXPECT_FALSE(mParser->validateMessage(request));
}

TEST_F(TestJsonRpcMessageParser, ValidateRequestMissingMethod)
{
    QJsonObject request = createValidRequest();
    request.remove("method"); // Missing method
    
    EXPECT_FALSE(mParser->validateMessage(request));
}

TEST_F(TestJsonRpcMessageParser, ValidateRequestMissingId)
{
    QJsonObject request = createValidRequest();
    request.remove("id"); // Missing id
    
    EXPECT_TRUE(mParser->validateMessage(request)); // Missing id will become notification
}

TEST_F(TestJsonRpcMessageParser, ValidateResponseMissingId)
{
    QJsonObject response = createValidResponse();
    response.remove("id"); // Missing id
    
    EXPECT_FALSE(mParser->validateMessage(response));
}

TEST_F(TestJsonRpcMessageParser, ValidateResponseWithBothResultAndError)
{
    QJsonObject response = createValidResponse();
    response["error"] = createErrorResponse().value("error"); // Both result and error
    
    EXPECT_FALSE(mParser->validateMessage(response));
}

TEST_F(TestJsonRpcMessageParser, ValidateResponseMissingBothResultAndError)
{
    QJsonObject response = createValidResponse();
    response.remove("result"); // Missing both result and error
    
    EXPECT_FALSE(mParser->validateMessage(response));
}

TEST_F(TestJsonRpcMessageParser, ValidateRequestWithNullId)
{
    QJsonObject request = createValidRequest();
    request["id"] = QJsonValue::Null; // Null id (invalid according to JSON-RPC 2.0)
    
    EXPECT_FALSE(mParser->validateMessage(request));
}

TEST_F(TestJsonRpcMessageParser, ValidateResponseWithNullId)
{
    QJsonObject response = createValidResponse();
    response["id"] = QJsonValue::Null; // Null id (invalid according to JSON-RPC 2.0)
    
    EXPECT_FALSE(mParser->validateMessage(response));
}

TEST_F(TestJsonRpcMessageParser, ValidateRequestWithStringParams)
{
    QJsonObject request = createValidRequest("testMethod", "stringParam");
    
    EXPECT_FALSE(mParser->validateMessage(request)); // String params are invalid
}

TEST_F(TestJsonRpcMessageParser, ValidateRequestWithNumberParams)
{
    QJsonObject request = createValidRequest("testMethod", 42);
    
    EXPECT_FALSE(mParser->validateMessage(request)); // Number params are invalid
}

TEST_F(TestJsonRpcMessageParser, ValidateRequestWithBooleanParams)
{
    QJsonObject request = createValidRequest("testMethod", true);
    
    EXPECT_FALSE(mParser->validateMessage(request)); // Boolean params are invalid
}

TEST_F(TestJsonRpcMessageParser, ValidateRequestWithNullParams)
{
    QJsonObject request = createValidRequest("testMethod", QJsonValue::Null);
    
    EXPECT_TRUE(mParser->validateMessage(request)); // Null params are valid
}

TEST_F(TestJsonRpcMessageParser, ParseMethodNameFromValidRequest)
{
    QJsonObject request = createValidRequest("testMethod");
    
    QString methodName = mParser->parseMethodName(request);
    
    EXPECT_EQ(methodName, "testMethod");
}

TEST_F(TestJsonRpcMessageParser, ParseMethodNameFromInvalidRequest)
{
    QJsonObject invalidRequest; // Empty object
    
    QString methodName = mParser->parseMethodName(invalidRequest);
    
    EXPECT_TRUE(methodName.isEmpty());
}

TEST_F(TestJsonRpcMessageParser, ParseParametersFromRequestWithArrayParams)
{
    QJsonArray paramsArray = QJsonArray{"param1", "param2", "param3"};
    QJsonObject request = createValidRequest("testMethod", paramsArray);
    
    // Since array params are now invalid, parseParameters should return empty object
    // because the message validation fails and parseParameters checks validation first
    QJsonValue params = mParser->parseParameters(request);
    
    EXPECT_TRUE(params.isObject());
    EXPECT_TRUE(params.toObject().isEmpty());
}

TEST_F(TestJsonRpcMessageParser, ParseParametersFromRequestWithObjectParams)
{
    QJsonObject paramsObject;
    paramsObject["param1"] = "value1";
    paramsObject["param2"] = 42;
    QJsonObject request = createValidRequest("testMethod", paramsObject);
    
    QJsonValue params = mParser->parseParameters(request);
    
    EXPECT_TRUE(params.isObject());
    EXPECT_TRUE(params.toObject().contains("param1"));
    EXPECT_TRUE(params.toObject().contains("param2"));
}

TEST_F(TestJsonRpcMessageParser, ParseParametersFromRequestWithoutParams)
{
    QJsonObject request = createValidRequest("testMethod"); // No params
    
    QJsonValue params = mParser->parseParameters(request);
    
    EXPECT_TRUE(params.toObject().isEmpty());
}

TEST_F(TestJsonRpcMessageParser, IsNotificationWithValidNotification)
{
    QJsonObject notification = createValidNotification();
    
    EXPECT_TRUE(mParser->isNotification(notification));
}

TEST_F(TestJsonRpcMessageParser, IsNotificationWithValidRequest)
{
    QJsonObject request = createValidRequest(); // Has id, so not notification
    
    EXPECT_FALSE(mParser->isNotification(request));
}

// Helper methods
QJsonObject TestJsonRpcMessageParser::createValidRequest
(const QString& method, const QJsonValue& params, const QVariant& id)
{
    QJsonObject request;
    request["jsonrpc"] = "2.0";
    request["method"] = method;
    
    if (!params.isNull()) {
        request["params"] = params;
    }
    
    if (id.isValid() && !id.isNull()) {
        request["id"] = QJsonValue::fromVariant(id);
    }
    
    return request;
}

QJsonObject TestJsonRpcMessageParser::createValidResponse
(const QVariant& id, const QJsonValue& result)
{
    QJsonObject response;
    response["jsonrpc"] = "2.0";
    response["id"] = QJsonValue::fromVariant(id);
    response["result"] = result;
    
    return response;
}

QJsonObject TestJsonRpcMessageParser::createValidNotification
(const QString& method, const QJsonValue& params)
{
    QJsonObject notification;
    notification["jsonrpc"] = "2.0";
    notification["method"] = method;
    
    if (!params.isNull()) {
        notification["params"] = params;
    }
    
    return notification;
}

QJsonObject TestJsonRpcMessageParser::createErrorResponse
(const QVariant& id, int code, const QString& message, const QJsonValue& data)
{
    QJsonObject error;
    error["code"] = code;
    error["message"] = message;
    
    if (!data.isNull()) {
        error["data"] = data;
    }
    
    QJsonObject response;
    response["jsonrpc"] = "2.0";
    response["id"] = QJsonValue::fromVariant(id);
    response["error"] = error;
    
    return response;
}
